#pragma once
#include <vector>
#include <map>
#include "IRunnable.h"
#include "UpdateProcess.h"
#include "RenderProcess.h"
#include "Configs.h"
#include "SoundManager.h"
#include "AniSystem.h"
#include "Menu.h"

namespace bs
{
	class InputSniffer;
	class Player;
	class Npc;
	class IMoveable;
	class Config;

	enum GameState
	{
		GS_MENU,
		GS_RUN,
		GS_WAIT_ANI,
		GS_QUIT
	};

	enum MenuCmd
	{
		MC_START,
		MC_AUTHOR,
		MC_QUIT
	};

	class Game : public IRunnable, public ICanvas, public IUpdateable,
		public IRenderable, public IMenuListener, public IAniSystemListener
	{
	public:
		Game(HWND wnd, InputSniffer& input);
		~Game();

		virtual void Run(int id, size_t time, size_t frames, size_t elapse, void* userData);

		virtual HDC PrepareToDraw();      // return the back dc
		virtual void FlushToScreen();

		virtual void Update(size_t time, size_t frames, size_t elapse);
		virtual void Render(HDC dc);

		virtual void OnAniBegin();
		virtual void OnAniEnd();

		virtual void OnClickItem(Menu* sender, int cmd);

		bool Init();
		void AddBullet(const char* name, const IMoveable& firer, bool left, bool isNpc);
		void AddExplode(const char* name, IMoveable& firer);
		void AddSound(const char* name);

		int GetWinWidth() { return this->clientRt.right; }
		int GetWinHeight() { return this->clientRt.bottom; }
		
	private:
		void LoadConfigs(Config& cfg, int& w, int& h);
		inline void AdjustWindowPos(int w, int h);
		inline void CreateDoubleBuffer();
		inline void DeleteDoubleBuffer();

		void DetectCollision();
		void UpdateNpcList(std::vector<Npc*>& npcList, int elapse, float speedFactor);

	private:
		int npcTimer;
		int npcMinHeight;
		int npcMaxHeight;

		Player* player;
		std::vector<Npc*> playerBullets;
		std::vector<Npc*> npcBullets;
		std::vector<Npc*> npcs;

		std::vector<NpcCfg> npcCfgs;
		std::map<std::string, NpcCfg> bulletCfgs;
		std::map<std::string, ExplodeCfg> explodeCfgs;

		GameState gs;
		Menu startMenu;

		InputSniffer& input;
		SoundManager sndManager;
		AniSystem aniSystem;

		RECT clientRt;

		HWND   gameWnd;
		HBRUSH backBr;
		HDC frontDc;
		HDC backDc;
		HBITMAP backBmp;
		HBITMAP oldBmp;
	};

}
